import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
import copy

# 设置matplotlib参数以正常显示中文和负号
plt.rcParams['axes.unicode_minus'] = False
plt.rcParams['font.sans-serif'] = ['SimHei']
# 加载数据
file_path = 'data/经济层面数据.xlsx'
sheets = pd.read_excel(file_path, sheet_name=None)


def mad(series,num=3): 
    '''去极值：中位数绝对值偏差去极值英文缩写为MAD,
    1). 找出因子的中位数 median；2). 得到每个因子值与中位数的绝对偏差值|x-median|
    3). 得到绝对偏差值的中位数，MAD, median(|x-median|)；4). 计算MAD_e = 1.4826*MAD,然后确定参数n, 作出调整
    通常把偏移设为 3倍MAD_e. 如果样本满足正态分布且足够大, 我们可以证明超过上下限的值为异常值''' 
    series = copy.copy(series) 
    if all(pd.isnull(series)):
        return series
    me = series.median() 
    mad = (series-me).abs().median() 
    MAD_e = 1.4826*mad  
    up = me+num*MAD_e
    down = me-num*MAD_e  
    series[series>up] = up 
    series[series<down] = down 
    return series 

def mad_df(df,num=3,axis=0):
    '''按列对dataframe的mad去极值
    axis=0是按列去极值，=1是按行去极值''' 
    df = copy.copy(df) 
    if axis==0:
        for col in df.columns:
            df[col] = mad(df[col],num=num) 
    elif axis==1: 
        for idx in df.index:
            df.loc[idx,:] = mad(df.loc[idx,:],num=num) 
    return df 

# 先对每个表格应用MAD去极值处理
for sheet_name, sheet in sheets.items():
    sheet['日期'] = pd.to_datetime(sheet['日期'], format='%Y-%m')
    sheets[sheet_name] = mad_df(sheet.set_index('日期'), num=3, axis=0)
    
    
# 转换日期列并找到公共日期范围
min_dates = []
max_dates = []
for sheet_name, sheet in sheets.items():
    sheet['日期'] = pd.to_datetime(sheet['日期'], format='%Y-%m')  
    sheet.set_index('日期', inplace=True)  
    min_dates.append(sheet.index.min())
    max_dates.append(sheet.index.max())

min_date = max(min_dates)
max_date = min(max_dates)
common_date_range = pd.date_range(start=min_date, end=max_date, freq='MS') #每月首日

# 对齐数据到公共日期范围并向前填充缺失值
for sheet_name, sheet in sheets.items():
    sheets[sheet_name] = sheet.reindex(common_date_range).ffill() 

# 将对齐数据合并到一个DataFrame中
combined_df = pd.concat(sheets.values(), axis=1)

# 初始化一个空列表用于存储图像
figures = []
#%% 法一：脉冲法
# 初始化用于存储经济增长因子的DataFrame
economic_growth_factors = pd.DataFrame(index=common_date_range)

# 定义环比变化打分函数
#比较三个月环比方向  确定1/-1/0
def calculate_score(pulse):
    scores = []
    monthly_changes = pulse.diff().dropna()
    for i in range(2, len(monthly_changes)):  # 从第三个月开始
        period = monthly_changes.iloc[i-2:i+1]  # 包括当前月和前两个月
        pos_count = (period > 0).sum()
        neg_count = (period < 0).sum()
        scores.append((pos_count - neg_count)/3)
    return pd.Series(scores, index=monthly_changes.index[2:])


# 遍历combined_df的每个列进行操作
for col in combined_df.columns:
    if '同比' in col:
        pulse = combined_df[col]
    else:
        # 对于非同比数据，首先计算滚动平均以平滑数据,然后计算同比
        smoothed_data = combined_df[col].rolling(window=12).mean()
        pulse = smoothed_data.pct_change(periods=12) * 100

 # 计算脉冲值的三个月环比变化方向并打分
    economic_growth_factors[col + '_脉冲'] = pulse
    economic_growth_factors[col + '_score'] = calculate_score(pulse)

# 计算所有指标得分的总和
score_columns = [col for col in economic_growth_factors.columns if '_score'  in col and 'PMI' in col]
aa1 = economic_growth_factors[score_columns].mean(axis=1) 
score_columns = [col for col in economic_growth_factors.columns if '_score'  in col and '工业增加值' in col]
aa2 = economic_growth_factors[score_columns].mean(axis=1) 

score_columns = ['工业增加值:当月同比_score']
aa3 = economic_growth_factors[score_columns].mean(axis=1) 

economic_growth_factors['Total_Score'] = aa3 #1*aa1+0*aa2+aa3

# 绘制经济增长因子的时间序列图
fig1, ax1 = plt.subplots(figsize=(14, 7))
ax1.axhline(0, color='black', linewidth=0.8)
ax1.fill_between(economic_growth_factors.index, economic_growth_factors['Total_Score'], where=(economic_growth_factors['Total_Score'] >= 0), color='red', alpha=0.3,label='经济上行')
ax1.fill_between(economic_growth_factors.index, economic_growth_factors['Total_Score'], where=(economic_growth_factors['Total_Score'] <= 0), color='green',alpha=0.3, label='经济下行')
ax1.set_xlabel('日期')
ax1.tick_params(axis='y', labelcolor='black')
ax1.legend(loc='upper left')

# 添加第二个Y轴绘制一些指标的脉冲数据
ax2 = ax1.twinx()
ax2.plot(economic_growth_factors.index, economic_growth_factors['非制造业PMI_脉冲'], label='非制造业PMI脉冲', alpha=0.7, color='blue')
ax2.plot(economic_growth_factors.index, economic_growth_factors['PMI_脉冲'], label='制造业PMI脉冲', alpha=0.7, color='orange')
ax2.set_ylabel('脉冲值(%)', color='black')
ax2.tick_params(axis='y', labelcolor='black')
ax2.legend(loc='upper right')

ax1.grid(True)
plt.title('脉冲法刻画经济增长因子')
figures.append(fig1)  # 将图像存入列表中
plt.show()


#%%MA比较法刻画经济增长因子
# 初始化一个DataFrame来存储每个指标的得分
ma_results = pd.DataFrame(index=combined_df.index)

# 遍历combined_df中的每一列
for col in combined_df.columns:
    # 对于每个指标，存储1到12个月的移动平均值
    for n in range(1, 13):
        ma_label = f'{col}_MA{n}'  # 为每个移动平均生成唯一列名
        ma_results[ma_label] = combined_df[col].rolling(window=n).mean()
    
    # 计算得分
    scores = []
    for i in range(combined_df.shape[0]):
        score = 0
        for n in range(1, 12):
            current_ma = f'{col}_MA{n}'
            next_ma = f'{col}_MA{n+1}'
            # 比较相邻的移动平均值
            if ma_results[current_ma].iloc[i] > ma_results[next_ma].iloc[i]:
                score += 1
            elif ma_results[current_ma].iloc[i] < ma_results[next_ma].iloc[i]:
                score -= 1
        scores.append(score)
    
    # 将得分添加到结果DataFrame
    ma_results[f'{col}_score'] = scores

# 计算总的经济增长因子
ma_results['Total_Score'] = ma_results[[col for col in ma_results.columns if col.endswith('_score')]].sum(axis=1)

# 以经济为例：五个维度，维度内你要动脑有逻辑一点权重，维度间就排列组合（可以有逻辑也可以没逻辑）

# 绘制总经济增长因子的水位图
fig2, ax = plt.subplots(figsize=(14, 7))
ax.fill_between(
    ma_results.index, ma_results['Total_Score'], 
    where=(ma_results['Total_Score'] > 0), 
    color='red', alpha=0.3, label='经济上行'
)
ax.fill_between(
    ma_results.index, ma_results['Total_Score'], 
    where=(ma_results['Total_Score'] < 0),
    color='green', alpha=0.3, label='经济下行'
)
ax.axhline(0, color='black', linestyle='--', label='基准线0')
plt.title('MA比较法刻画经济增长因子')
plt.xlabel('日期')
plt.ylabel('经济增长因子')
plt.legend()
plt.grid()
plt.tight_layout()
figures.append(fig2)  # 将图像存入列表中
plt.show()
#%%扩散指数法
# 初始化存储扩散指数的 DataFrame
diffusion_indices = pd.DataFrame(index=combined_df.index)

# 遍历 combined_df 的每个列
for col in combined_df.columns:
    if '同比' in col:
        # 对于同比数据，直接使用
        yoy_data = combined_df[col]
    else:
        # 对于非同比数据，先计算滚动平均以平滑数据，再计算同比变化
        smoothed_data = combined_df[col].rolling(window=12).mean()
        yoy_data = smoothed_data.pct_change(periods=12) * 100
    
    # 转换为扩散值：1 表示同比变化 > 0，0 表示同比变化 <= 0
    diffusion_indices[col] = (yoy_data.diff() > 0).astype(int)

# 计算扩散指数：正值数量 / 指标总数 * 100
diffusion_indices['扩散指数'] = diffusion_indices.mean(axis=1) * 100

# 绘制扩散指数的水位图
fig3, ax = plt.subplots(figsize=(14, 7))  # 创建新的图像对象
ax.fill_between(
    diffusion_indices.index, 
    diffusion_indices['扩散指数'], 
    50,  # 基准线
    where=(diffusion_indices['扩散指数'] > 50), 
    color='red', alpha=0.3, label='经济扩张'
)

ax.fill_between(
    diffusion_indices.index, 
    diffusion_indices['扩散指数'], 
    50,  # 基准线
    where=(diffusion_indices['扩散指数'] < 50), 
    color='green', alpha=0.3, label='经济收缩'
)

# 添加基准线
ax.axhline(50, color='black', linestyle='--', linewidth=1, label='基准线 50')

# 添加标题和标签
ax.set_title('扩散指数法刻画经济增长因子', fontsize=14)
ax.set_xlabel('日期', fontsize=12)
ax.set_ylabel('扩散指数 (%)', fontsize=12)
ax.legend()
ax.grid(True)
plt.tight_layout()

figures.append(fig3)  # 将图像存入列表中
plt.show()

#%%图片存储下来
# 将所有图像保存到 PDF 文件
output_pdf = "output/经济增长因子.pdf"
with PdfPages(output_pdf) as pdf:
    for fig in figures:
        pdf.savefig(fig)
        plt.close(fig)  

